/*
    Down In Front: The Android Application
    This application is an interface for Down In Front commentaries.
    Copyright (C) 2011
    Holden Hill <holdenhill@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package down.in.front;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.PowerManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.ViewFlipper;

/**
 * This is the activity that holds the bulk of the app. For now, all of the
 * player actions are tightly integrated within this activity. The intention is
 * to move any player references into a service to allow people to switch in and
 * out of this activity without killing playback.
 * 
 * It's a work in progress.
 * 
 * @author Holden Hill <holdenhill@gmail.com>
 * 
 */
public class ReleaseView extends Activity implements OnClickListener,
		OnTouchListener, OnPreparedListener, OnSeekCompleteListener,
		OnBufferingUpdateListener, OnCompletionListener {

	// Global variables associated with touch listening.
	private int current = 0, offset = 0;
	private double temp = 0.0, tempPos = 0.0, touch = 0.0;
	private final int SWIPE_MIN = 100;
	private final int SWIPE_PATH = 200;
	private final int SWIPE_X = 200;

	// Stores the title for the episode currently in the player.
	private String currentTitle;

	// Tracks down the SD for file storage.
	private final File ROOT = Environment.getExternalStorageDirectory();

	// Create UI elements.
	private Animation leftIn, leftOut;
	private Animation rightIn, rightOut;
	private Button playFromStream, playFromDownload;
	private Button slider, playButton;
	private DisplayMetrics screenSize;
	private GestureDetector gestureDetector;
	private ImageView bgImage1, bgImage2, bgImage3;
	private ImageView containerBar, playingBar, bufferedBar;
	private TextView titleView1, titleView2, titleView3;
	private TextView commView1, commView2, commView3;
	private TextView descView1, descView2, descView3;
	private TextView currentTime, endTime;
	private TextView showPlaying;
	private ViewFlipper flipper;

	// Create elements associated with audio playback.
	private Handler timeHandler;
	private MediaPlayer player;
	private PowerManager powerManager;
	private PowerManager.WakeLock wake;

	// Create the list containing all episode data.
	private ArrayList<Episode> episodes;

	// Create the intent for the download service.
	private Intent intent;

	/**
	 * Runs on start up. Sets all of the UI elements, assigns a listener for the
	 * screen swiping. Also reads in data from the web and parses it into
	 * seperate arraylists.
	 * 
	 * @param savedInstanceState
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// Establish the wake lock for audio streaming.
		powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
		wake = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
				"Stream Lock");
		Log.i("DOWN IN FRONT : INIT", "Set up Wake Lock for streaming.");

		// Misc UI constructors.
		current = ArchiveView.current;
		episodes = ArchiveView.episodes;
		flipper = (ViewFlipper) findViewById(R.id.flipper);
		gestureDetector = new GestureDetector(new MyGestureDetector());
		player = new MediaPlayer();
		screenSize = new DisplayMetrics();
		timeHandler = new Handler();
		Log.i("DOWN IN FRONT : INIT", "Created data objects.");

		// Animations for swiping.
		leftIn = AnimationUtils.loadAnimation(this, R.anim.left_in);
		leftOut = AnimationUtils.loadAnimation(this, R.anim.left_out);
		rightIn = AnimationUtils.loadAnimation(this, R.anim.right_in);
		rightOut = AnimationUtils.loadAnimation(this, R.anim.right_out);
		Log.i("DOWN IN FRONT : INIT", "Loaded animations.");

		// Buttons and listeners.
		playFromDownload = (Button) findViewById(R.id.downloadButton);
		playFromStream = (Button) findViewById(R.id.streamButton);
		slider = (Button) findViewById(R.id.handle);
		playButton = (Button) findViewById(R.id.playerButton);
		playFromDownload.setOnClickListener(this);
		playFromStream.setOnClickListener(this);
		playButton.setOnClickListener(this);
		player.setOnPreparedListener(this);
		player.setOnSeekCompleteListener(this);
		player.setOnBufferingUpdateListener(this);
		player.setOnCompletionListener(this);
		Log.i("DOWN IN FRONT : INIT", "Loaded buttons.");

		// Background images for each flipper.
		bgImage1 = (ImageView) findViewById(R.id.bgImage1);
		bgImage2 = (ImageView) findViewById(R.id.bgImage2);
		bgImage3 = (ImageView) findViewById(R.id.bgImage3);
		containerBar = (ImageView) findViewById(R.id.progressBar);
		playingBar = (ImageView) findViewById(R.id.playedBar);
		bufferedBar = (ImageView) findViewById(R.id.streamedBar);
		Log.i("DOWN IN FRONT : INIT", "Loaded images.");

		// Set all of the text views.
		commView1 = (TextView) findViewById(R.id.commView1);
		commView2 = (TextView) findViewById(R.id.commView2);
		commView3 = (TextView) findViewById(R.id.commView3);
		descView1 = (TextView) findViewById(R.id.descView1);
		descView2 = (TextView) findViewById(R.id.descView2);
		descView3 = (TextView) findViewById(R.id.descView3);
		showPlaying = (TextView) findViewById(R.id.showPlaying);
		titleView1 = (TextView) findViewById(R.id.titleView1);
		titleView2 = (TextView) findViewById(R.id.titleView2);
		titleView3 = (TextView) findViewById(R.id.titleView3);
		currentTime = (TextView) findViewById(R.id.currentTime);
		endTime = (TextView) findViewById(R.id.endTime);
		Log.i("DOWN IN FRONT : INIT", "Loaded text fields.");

		// Set fonts for all of the text fields.
		Typeface tf = Typeface.createFromAsset(getAssets(),
				"fonts/WHOOPASS.TTF");
		Typeface tf2 = Typeface
				.createFromAsset(getAssets(), "fonts/tahoma.ttf");
		Typeface tf3 = Typeface.createFromAsset(getAssets(),
				"fonts/tahomabd.ttf");
		commView1.setTypeface(tf3);
		commView2.setTypeface(tf3);
		commView3.setTypeface(tf3);
		descView1.setTypeface(tf2);
		descView2.setTypeface(tf2);
		descView3.setTypeface(tf2);
		showPlaying.setTypeface(tf);
		titleView1.setTypeface(tf);
		titleView2.setTypeface(tf);
		titleView3.setTypeface(tf);
		currentTime.setTypeface(tf3);
		endTime.setTypeface(tf3);
		Log.i("DOWN IN FRONT : INIT", "Loaded typefaces.");

		// Set information for the first panel.
		bgImage1.setBackgroundDrawable(LoadImage(episodes.get(current)
				.getBackgroundLink()));
		titleView1.setText(episodes.get(current).getTitle());
		commView1.setText(episodes.get(current).getCommentators());
		descView1.setText(episodes.get(current).getDescription());

		// Determine what functionality to give the download button.
		File downloaded = new File(ROOT,//
				"/DownInFront/audio-" + (current + 1) + ".mp3");
		if (downloaded.exists()) {
			playFromDownload
					.setBackgroundResource(R.drawable.app_play_download);
		}

		// Automatically begins to download the current episode's file for
		// streaming.
		try {
			player.setDataSource(episodes.get(current).getPlayerLink());
			showPlaying.setText(episodes.get(current).getTitle());
		} catch (IOException e1) {
			Log.w("DOWN IN FRONT : SETDATASOURCE",
					"Failed to begin streaming. Please check for a data connection.");
			showPlaying.setText("Cannot locate file.");
		}

		// Set the rest of the information for the player pane at the bottom of
		// the UI.
		currentTitle = episodes.get(current).getTitle();
		currentTime.setText("0:00:00");
		endTime.setText("-0:00:00");
		Log.i("DOWN IN FRONT : INIT", "Panel 1 set.");

		try {
			// Set information for the second panel. This starts as the panel to
			// the
			// right of the first pane.
			titleView2.setText(episodes.get(current + 1).getTitle());
			commView2.setText(episodes.get(current + 1).getCommentators());
			descView2.setText(episodes.get(current + 1).getDescription());
			bgImage2.setBackgroundDrawable(LoadImage(episodes.get(current + 1)
					.getBackgroundLink()));
			Log.i("DOWN IN FRONT : INIT", "Panel 2 set.");
		} catch (IndexOutOfBoundsException ioe) {
			// Does nothing. This is designed to catch the ends of the list.
			Log.i("DOWN IN FRONT : INIT", "Panel 2 does not exist.");
		}

		try {
			// Set information for the third panel. This starts as the panel to
			// the
			// left of the first pane.
			titleView3.setText(episodes.get(current - 1).getTitle());
			commView3.setText(episodes.get(current - 1).getCommentators());
			descView3.setText(episodes.get(current - 1).getDescription());
			bgImage3.setBackgroundDrawable(LoadImage(episodes.get(current - 1)
					.getBackgroundLink()));
			Log.i("DOWN IN FRONT : INIT", "Panel 3 set.");
		} catch (IndexOutOfBoundsException ioe) {
			// Does nothing. This is designed to catch the ends of the list.
			Log.i("DOWN IN FRONT : INIT", "Panel 3 does not exist.");
		}

		// Create a listener for swiping.
		new View.OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (gestureDetector.onTouchEvent(event)) {
					return true;
				}
				return false;
			}
		};
	}

	/**
	 * Handle button clicks, usually relating to pausing and playing.
	 */
	@Override
	public void onClick(View v) {
		// Log button clicks.
		Log.i("DOWN IN FRONT : ONCLICK",
				"getCurrentPosition():" + player.getCurrentPosition());

		try {
			// Checks if the 'play' button in the player pane was pressed.
			if (v.equals(playButton)) {
				if (player.isPlaying()) {
					// If playing.
					Log.i("DOWN IN FRONT : ONCLICK", "Pausing playback.");
					player.pause();
					playButton.setBackgroundResource(R.drawable.playbutton);

					if (wake.isHeld()) {
						wake.release();
						Log.i("DOWN IN FRONT : WAKELOCK",
								"Wake lock has been released.");
					}

					// Trigger handler for UI updates.
					timeHandler.removeCallbacks(timeTask);
				} else if (player.getCurrentPosition() > 0
						&& player.getCurrentPosition() < player.getDuration()) {
					// If paused.
					Log.i("DOWN IN FRONT : ONCLICK",
							"Starting playback from buffered position.");
					player.start();
					playButton.setBackgroundResource(R.drawable.pausebutton);

					if (!wake.isHeld()) {
						wake.acquire();
						Log.i("DOWN IN FRONT : WAKELOCK",
								"Wake lock has been acquired.");
					}

					// Trigger handler for UI updates.
					timeHandler.postDelayed(timeTask, 1);
				} else {
					// If new.
					Log.i("DOWN IN FRONT : ONCLICK",
							"Starting playback from beginning of file.");
					player.prepareAsync();
					showPlaying.setText("Buffering ...");
					currentTitle = episodes.get(current).getTitle();
					playButton.setBackgroundResource(R.drawable.pausebutton);
					playButton.setClickable(false);
				}
			} else if (v.equals(playFromStream)) {
				if (player.isPlaying()) {
					player.stop();
					player.reset();
				} else if (!player.isPlaying()) {
					player.reset();
				}

				// Reset all player and player pane attributes for a new file.
				player.setDataSource(episodes.get(current).getPlayerLink());
				player.prepareAsync();
				slider.setOnTouchListener(null);
				showPlaying.setText("Buffering ...");
				currentTitle = episodes.get(current).getTitle();
				playButton.setClickable(false);
				playButton.setBackgroundResource(R.drawable.pausebutton);
				playingBar.getLayoutParams().width = 0;
				playingBar.requestLayout();
				bufferedBar.getLayoutParams().width = 0;
				bufferedBar.requestLayout();
				RelativeLayout.LayoutParams ivParams = (android.widget.RelativeLayout.LayoutParams) slider
						.getLayoutParams();
				ivParams.leftMargin = 7;
				slider.setLayoutParams(ivParams);
				slider.requestLayout();
				currentTime.setText("0:00:00");
				endTime.setText("-0:00:00");
				tempPos = 0.0;
				temp = 0.0;
			} else if (v.equals(playFromDownload)) {
				File downloaded = new File(ROOT,//
						"/DownInFront/audio-" + (current + 1) + ".mp3");

				// If the file doesn't exist, download it to the SD Card.
				if (!downloaded.exists()) {
					// Store episode information in the intent for the new
					// service
					intent = new Intent(this, DownloadService.class);
					intent.putExtra("id", episodes.get(current).getID());
					intent.putExtra("title", episodes.get(current).getTitle());
					intent.putExtra("playerLink", episodes.get(current)
							.getPlayerLink());

					// Start that sucker.
					Log.i("DOWN IN FRONT : DOWNLOAD", "Starting service.");
					startService(intent);
					registerReceiver(broadcastReceiver, new IntentFilter(
							DownloadService.DOWNLOAD_ACTION));
				} else {
					// Play from existing file on the SD Card.
					Log.i("DOWN IN FRONT : PLAY", downloaded.toString());
					String filepath = ROOT.toString() + "/DownInFront/audio-"
							+ (current + 1) + ".mp3";
					Log.i("DOWN IN FRONT", "File Path: " + filepath);
					player.stop();
					player.reset();
					player.setDataSource(filepath);
					player.prepareAsync();
					bufferedBar.getLayoutParams().width = containerBar
							.getWidth();
					playButton.setBackgroundResource(R.drawable.pausebutton);
				}
			}
		} catch (IOException e) {
			showPlaying.setText("Cannot load audio file.");
			Log.w("DOWN IN FRONT : ONCLICK",
					"Audio file was not found or could not be loaded.");
		}
	}

	/**
	 * Handles touch events.
	 */
	@Override
	public boolean onTouch(View v, MotionEvent e) {
		// If the slider on the progress bar is moved.
		if (v.equals(slider)) {
			int secs, size = 0;
			switch (e.getAction()) {

			// Action event for sliding the bar back and forth.
			case MotionEvent.ACTION_MOVE: {
				size = containerBar.getWidth();
				offset = (int) (e.getX() - touch);

				// Check bounds.
				if ((slider.getLeft() + offset) > 7
						&& (slider.getRight() - offset) < (containerBar
								.getRight() + 7)) {
					slider.layout(slider.getLeft() + offset, slider.getTop(), //
							slider.getRight() + offset, slider.getBottom());
				}

				// Convert from position to seconds.
				temp = e.getRawX() - 19;
				double percent = temp / size;
				double milli = percent * player.getDuration();
				secs = (int) milli / 1000;

				Log.i("DOWN IN FRONT : SEEKBAR",
						"slider.getLeft(): " + slider.getLeft());
				Log.i("DOWN IN FRONT : SEEKBAR", "e.getX(): " + e.getX());
				Log.i("DOWN IN FRONT : SEEKBAR", "offset: " + offset);
				Log.i("DOWN IN FRONT : SEEKBAR", "e.getRawX(): " + e.getRawX());
				Log.i("DOWN IN FRONT : SEEKBAR", "current x: " + temp + ", %: "//
						+ percent + ", " + secs + " seconds");
				break;
			}
				// Press down.
			case MotionEvent.ACTION_DOWN: {
				touch = e.getX();
				break;
			}
				// Release the bar.
			case MotionEvent.ACTION_UP: {
				size = containerBar.getWidth();
				if (temp > bufferedBar.getWidth()) {
					temp = bufferedBar.getWidth();

					if (temp < 0) {
						temp = 0;
					}
				}

				// More conversions.
				double percent = temp / size;
				double seekto = percent * (double) player.getDuration();
				RelativeLayout.LayoutParams layout = (android.widget.RelativeLayout.LayoutParams) slider
						.getLayoutParams();
				Log.i("DURATION TEST",
						"Duration of current track is " + player.getDuration()
								+ ".");
				Log.i("SEEK TEST", "current x: " + temp + ", %: " + percent
						+ ", " + (int) (seekto / 1000) + " seconds");

				tempPos = temp;
				layout.leftMargin = (int) (7 + tempPos);
				playingBar.getLayoutParams().width = (int) tempPos;
				playingBar.requestLayout();
				player.seekTo((int) seekto);
				break;
			}
			}
		}
		return false;
	}

	/**
	 * Updates the UI elements based on the player position.
	 */
	private Runnable timeTask = new Runnable() {
		@Override
		public void run() {
			if (player.isPlaying()) {
				// Update player bar.
				int size = containerBar.getWidth();
				RelativeLayout.LayoutParams layout = (android.widget.RelativeLayout.LayoutParams) slider
						.getLayoutParams();

				tempPos += (double) (size * 1000)
						/ (double) player.getDuration();
				layout.leftMargin = (int) (7 + tempPos);

				// Update all the text fields.
				currentTime.setText(formatTime(player.getCurrentPosition()));
				endTime.setText("-"
						+ formatTime(player.getDuration()
								- player.getCurrentPosition()));
				playingBar.getLayoutParams().width = (int) tempPos;
				slider.setLayoutParams(layout);
				playingBar.requestLayout();
				slider.requestLayout();
				timeHandler.postDelayed(this, 1000);
			}
		}
	};

	/**
	 * Update each flipper every time the screen is swiped. This allows us to
	 * only have three pages of data open at any given time, saving quite a bit
	 * of our precious resources.
	 */
	public void update() {
		try {
			if (flipper.getCurrentView().equals(findViewById(R.id.tView1))) {
				bgImage2.setBackgroundDrawable(LoadImage(episodes.get(
						current + 1).getBackgroundLink()));
				titleView2.setText(episodes.get(current + 1).getTitle());
				commView2.setText(episodes.get(current + 1).getCommentators());
				descView2.setText(episodes.get(current + 1).getDescription());

				bgImage3.setBackgroundDrawable(LoadImage(episodes.get(
						current - 1).getBackgroundLink()));
				titleView3.setText(episodes.get(current - 1).getTitle());
				commView3.setText(episodes.get(current - 1).getCommentators());
				descView3.setText(episodes.get(current - 1).getDescription());
			} else if (flipper.getCurrentView().equals(
					findViewById(R.id.tView2))) {
				bgImage3.setBackgroundDrawable(LoadImage(episodes.get(
						current + 1).getBackgroundLink()));
				titleView3.setText(episodes.get(current + 1).getTitle());
				commView3.setText(episodes.get(current + 1).getCommentators());
				descView3.setText(episodes.get(current + 1).getDescription());

				bgImage1.setBackgroundDrawable(LoadImage(episodes.get(
						current - 1).getBackgroundLink()));
				titleView1.setText(episodes.get(current - 1).getTitle());
				commView1.setText(episodes.get(current - 1).getCommentators());
				descView1.setText(episodes.get(current - 1).getDescription());
			} else if (flipper.getCurrentView().equals(
					findViewById(R.id.tView3))) {
				bgImage1.setBackgroundDrawable(LoadImage(episodes.get(
						current + 1).getBackgroundLink()));
				titleView1.setText(episodes.get(current + 1).getTitle());
				commView1.setText(episodes.get(current + 1).getCommentators());
				descView1.setText(episodes.get(current + 1).getDescription());

				bgImage2.setBackgroundDrawable(LoadImage(episodes.get(
						current - 1).getBackgroundLink()));
				titleView2.setText(episodes.get(current - 1).getTitle());
				commView2.setText(episodes.get(current - 1).getCommentators());
				descView2.setText(episodes.get(current - 1).getDescription());
			}
		} catch (Exception e) {
			// Do nothing! This prevents the app from moving past its
			// boundaries.
		}
	}

	/**
	 * Check for hardware button presses.
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// Overrides the back button to display a warning dialog to the user.
		if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setMessage(
					"Are you sure you want to return to the episode list? This will end the current commentary.")
					.setCancelable(false)
					.setPositiveButton("Yes",
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog,
										int id) {
									ReleaseView.this.finish();
								}
							})
					.setNegativeButton("No",
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog,
										int id) {
									dialog.cancel();
								}
							});
			builder.show();
			return true;
		}

		return super.onKeyDown(keyCode, event);
	}

	/**
	 * Handles all of the swiping actions.
	 */
	class MyGestureDetector extends SimpleOnGestureListener {
		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float x, float y) {
			getWindowManager().getDefaultDisplay().getMetrics(screenSize);

			if (Math.abs(e1.getY() - e2.getY()) < SWIPE_PATH
					&& e1.getY() < (screenSize.heightPixels - 100)) {

				// Right to Left.
				if (e1.getX() - e2.getX() > SWIPE_MIN && Math.abs(x) > SWIPE_X
						&& current < (episodes.size() - 1)) {
					current++;
					flipper.setInAnimation(leftIn);
					flipper.setOutAnimation(leftOut);
					flipper.showNext();
					update();

				} else if (e2.getX() - e1.getX() > SWIPE_MIN
						&& Math.abs(x) > SWIPE_X && current > 0) {
					// Left to Right
					current--;
					flipper.setInAnimation(rightIn);
					flipper.setOutAnimation(rightOut);
					flipper.showPrevious();
					update();
				}
			}

			// Checks if the new current panel has a downloaded commentary or
			// not.
			File downloaded = new File(ROOT,//
					"/DownInFront/audio-" + (current + 1) + ".mp3");
			if (downloaded.exists()) {
				playFromDownload
						.setBackgroundResource(R.drawable.app_play_download);
			} else {
				playFromDownload.setBackgroundResource(R.drawable.app_download);
			}

			return false;
		}
	}

	/**
	 * Formats time from milliseconds into a common format for displaying
	 * playback status.
	 * 
	 * @param mil
	 *            The milliseconds to be formatted.
	 * @return A String containing a prettier version of the ms.
	 */
	private String formatTime(int mil) {
		// Calculations!
		int seconds = mil / 1000;
		int hours = seconds / 3600;
		seconds -= hours * 3600;
		int minutes = ((int) seconds) / 60;
		seconds -= minutes * 60;

		// Generate a String with the proper formatting information.
		String format = "" + hours + ":" + String.format("%02d", minutes) + ":"
				+ String.format("%02d", seconds);

		return format;
	}

	/**
	 * Creates a drawable image based on internal file locations.
	 * 
	 * @param filePath
	 *            A String containing the path to the image.
	 * @return An image to be drawn on the UI.
	 */
	private Drawable LoadImage(String filePath) {
		try {
			return Drawable.createFromPath(filePath);
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public void onConfigurationChanged(Configuration keyboard) {
		super.onConfigurationChanged(keyboard);
	};

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (gestureDetector.onTouchEvent(event))
			return true;
		else {
			return false;
		}
	}

	/**
	 * Overrides onDestroy to kill the wake lock and close out any UI handlers.
	 */
	@Override
	public void onDestroy() {
		super.onDestroy();

		timeHandler.removeCallbacks(timeTask);
		player.stop();
		player.release();
		if (wake.isHeld()) {
			wake.release();
			Log.i("DOWN IN FRONT : WAKELOCK", "Wake lock has been released.");
		}
	}

	@Override
	public void onPrepared(MediaPlayer arg0) {
		Log.i("DOWN IN FRONT : ONPREPARED",
				"Player prepared. Let's play some commentaries!");
		showPlaying.setText(currentTitle);
		player.start();
		if (!wake.isHeld()) {
			wake.acquire();
			Log.i("DOWN IN FRONT : WAKELOCK", "Wake lock has been acquired.");
		}
		playButton.setClickable(true);
		slider.setOnTouchListener(this);
		tempPos = 0.0;
		timeHandler.postDelayed(timeTask, 1);
		endTime.setText(formatTime(player.getDuration()));
	}

	@Override
	public void onSeekComplete(MediaPlayer arg0) {
		Log.i("DOWN IN FRONT : ONSEEKCOMPLETE",
				"Sup, made it to onSeekComplete.");
		Log.i("DOWN IN FRONT : ONSEEKCOMPLETE",
				"" + player.getCurrentPosition());
		if (player.isPlaying())
			playButton.setBackgroundResource(R.drawable.pausebutton);
	}

	@Override
	public void onBufferingUpdate(MediaPlayer mp, int buffered) {
		// Print buffering status.
		Log.i("DOWN IN FRONT : BUFFERING", "Oh hi, buffering update. We're at "
				+ buffered + "% now.");
		double size = (double) containerBar.getWidth() / 100.00;
		bufferedBar.getLayoutParams().width = (int) (size * (double) buffered);
		Log.i("DOWN IN FRONT : BUFFERING", "" + bufferedBar.getWidth());
		bufferedBar.requestLayout();
	}

	@Override
	public void onCompletion(MediaPlayer arg0) {
		if (wake.isHeld()) {
			wake.release();
			Log.i("DOWN IN FRONT", "Wake lock has been released.");
		}

		// Resets the player when playback is complete.
		RelativeLayout.LayoutParams layout = (android.widget.RelativeLayout.LayoutParams) slider
				.getLayoutParams();
		layout.leftMargin = 7;
		slider.setLayoutParams(layout);
		playingBar.getLayoutParams().width = 0;
		playButton.setBackgroundResource(R.drawable.playbutton);
		playingBar.requestLayout();
		slider.requestLayout();
		timeHandler.removeCallbacks(timeTask);
		tempPos = 0.0;
		temp = 0.0;
		currentTime.setText("0:00:00");
	}

	/**
	 * Updates the download button when the file download is complete.
	 */
	private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent.getBooleanExtra("finished", false) == true) {
				playFromDownload
						.setBackgroundResource(R.drawable.app_play_download);
				unregisterReceiver(broadcastReceiver);
			}
		}
	};
}